<?php

namespace Lib\View;

use Lib\Util\Util,
    Lib\Exception\NotFoundException,
    Lib\View\Helper\Helper,
    Lib\Controller\Controller;

class View {
    public static $error = true;

    private static $controller;

    private $layoutData = array(
        'css' => array(),
        'js' => array(),
        'meta' => array()
    );
    
    private static $instance;
    public static function getInstance() {
        if (! self::$instance)
            self::$instance = new self;

        return self::$instance;
    }

    public static function render($view, $layout = 'public', $vars = array(), $silent = false) {
        $inst = self::getInstance();

        // fetch content view
        $content = $inst->fetch($view, $vars);
        if ($layout === false) {
            return $content;
        }

        // fetch complete layout
        $layout = 'Layouts' . DS . $layout;
        return $inst->fetch($layout, array_merge($vars, array(
            '__content' => $content
        )));
    }

    public static function setController(Controller $controller) {
        self::$controller = $controller;
    }

    public static function getLayoutTitle() {
        $title = '';
        if (isset(self::$controller->title)) {
            $title = ' &raquo; ' . self::$controller->title;
        }

        return $title;
    }

    public function __get($name) {
        $className = preg_replace('/^help/', '', $name);

        if (isset($this->$className)) {
            return $this->$className;
        }

        // it's helper, load it
        if (preg_match('/^help/', $name)) {
            $helper = $this->getHelper($className);
            if (! $helper) {
                $helper = new Helper;
            }
            $this->$name = $helper;
            return $this->$name;
        }

        // layout includes
        if (preg_match('/^layout/', $name)) {
            switch($name) {
                case 'layoutStyles':
                    return implode("\n", $this->layoutData['css']);
                    break;

                case 'layoutScripts':
                    return implode("\n", $this->layoutData['js']);
                    break;

                case 'layoutMeta':
                    return implode("\n", $this->layoutData['meta']);
                    break;
            }
        }
    }

    public function layoutStyle($cssFilename, $media = 'screen') {
        $this->layoutData['css'][] = sprintf('<link rel="stylesheet" type="text/css" media="%s" href="%s">',
                                                $media, $cssFilename);
    }
    public function layoutScript($jsFilename) {
        $this->layoutData['js'][] = sprintf('<script type="text/javascript" src="%s"></script>', $jsFilename);
    }

    private function getPath($view) {
        return DIR_VIEW . DS . $view . ".php";
    }

    private function setVars(array $vars) {

    }

    private function fetch($view, $vars = array()) {
        $path = $this->getPath($view);
        
        // set vars
        foreach ($vars as $name => $value) {
            $$name = $value;
        }

        if (! file_exists($path)) {
            throw new NotFoundException("View {$view}");
        }

        $previousOutput = ob_get_contents();
        ob_clean();

        include $path;
        $html = ob_get_contents();
        ob_clean();

        echo $previousOutput;

        return $html;
    }

    private function getHelper($name) {
        $places = array(
           'App\\View\\Helper' => implode(DS, array(DIR_VIEW, "Helper", $name . ".php")),
           'Lib\\View\\Helper' => implode(DS, array(DIR_LIB, "View", "Helper", $name . ".php"))
        );

        foreach ($places as $namespace => $path) {
            if (file_exists($path)) {
                //require $path;
                $class = $namespace . "\\" . $name;
                $helper = new $class;
                return $helper;
            }
        }

        return false;
    }
}